/* libfake437 - a library for the rendering of code page 437 `graphics'
 * Copyright (C) 2008, 2009 Jack Kelly <endgame.dos@gmail.com>
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"
#include <SDL.h>
#include "fake437/types.h"
#include "fake437/primitive.h"
#include "defaults.h"

/* As seen in the SDL examples */
static void putpixel(SDL_Surface* surface, int x, int y, Uint32 pixel) {
  int bpp = surface->format->BytesPerPixel;
  /* Here p is the address to the pixel we want to set */
  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
  if (x < 0 || x >= surface->w || y < 0 || y >= surface->h) return;
  switch(bpp) {
  case 1:
    *p = pixel;
    break;
  case 2:
    *(Uint16*)p = pixel;
    break;
  case 3:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    p[0] = (pixel >> 16) & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = pixel & 0xff;
#else
    p[0] = pixel & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = (pixel >> 16) & 0xff;
#endif
    break;
  case 4:
    *(Uint32*)p = pixel;
    break;
  }
}

void f437_put_char(SDL_Surface* surface,
                   Sint32 x, Sint32 y, unsigned char ch,
                   F437Color fg, F437Color bg) {
  const SDL_Color* bg_color = NULL;
  const SDL_Color* fg_color = NULL;
  Uint32 bg_real = 0;
  Uint32 fg_real = 0;
  if (fg != F437_COLOR_TRANSPARENT) {
    fg_color = f437_get_color(fg);
    fg_real = SDL_MapRGB(surface->format,
                         fg_color->r, fg_color->g, fg_color->b);
  }
  if (bg != F437_COLOR_TRANSPARENT) {
    bg_color = f437_get_color(bg);
    bg_real = SDL_MapRGB(surface->format,
                         bg_color->r, bg_color->g, bg_color->b);
  }
  const F437Char* ch_real = f437_get_char(ch);
  int x_pixel;
  int y_pixel;
  if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
  for (y_pixel = 0 ; y_pixel < F437_CHAR_HEIGHT ; y_pixel++) {
    for (x_pixel = 0 ; x_pixel < F437_CHAR_WIDTH ; x_pixel++) {
      if ((*ch_real)[y_pixel][x_pixel] && fg != F437_COLOR_TRANSPARENT) {
        putpixel(surface, x_pixel + x, y_pixel + y, fg_real);
      } else if (bg != F437_COLOR_TRANSPARENT) {
        putpixel(surface, x_pixel + x, y_pixel + y, bg_real);
      }
    }
  }
  if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
}

void f437_put_rect(SDL_Surface* surface,
                   Sint32 x, Sint32 y, Uint32 width, Uint32 height,
                   unsigned char ch, F437Color fg, F437Color bg) {
  if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
  for (unsigned int y_char = 0 ; y_char < height ; y_char++) {
    for (unsigned int x_char = 0 ; x_char < width ; x_char++) {
      f437_put_char(surface,
                    x + x_char * F437_CHAR_WIDTH,
                    y + y_char * F437_CHAR_HEIGHT,
                    ch, fg, bg);
    }
  }
  if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
}

void f437_put_string(SDL_Surface* surface,
                     Sint32 x, Sint32 y, const char* string,
                     F437Color fg, F437Color bg) {
  if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface);
  int i = 0;
  for (const char* c = string ; *c ; c++, i++) {
    f437_put_char(surface, x + i * F437_CHAR_WIDTH, y, *c, fg, bg);
  }
  if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface);
}
